﻿using System;
using System.Diagnostics;
using System.Reflection;
using System.Text;

namespace gt.framework.Log
{
    public class TraceLogWrapper : ILogWrapper
    {
        private TraceSource m_source = null;

        public TraceLogWrapper(string name, SourceLevels level)
        {
            this.m_source = new TraceSource(name);
            this.m_source.Switch = new SourceSwitch(name);
            this.m_source.Switch.Level = level;
        }
        public TraceLogWrapper(string name, SourceLevels level, TraceListener listener)
            : this(name, level, new TraceListener[] { listener })
        {
        }
        public TraceLogWrapper(string name, SourceLevels level, TraceListener[] listeners)
        {
            this.m_source = new TraceSource(name);
            this.m_source.Listeners.AddRange(listeners);
            this.m_source.Switch = new SourceSwitch(name);
            this.m_source.Switch.Level = level;
        }
        public TraceLogWrapper(TraceSource source)
        {
            this.m_source = source;
        }

        public string Name => this.m_source.Name;

        public void Debug(string msg)
        {
            this.m_source.TraceEvent(TraceEventType.Verbose, 0, msg);
        }

        public void Error(Exception ex)
        {
            var msg = FormatException(ex);
            this.m_source.TraceEvent(TraceEventType.Error, 1, msg);
        }

        public void Error(string errorMsg, Exception ex)
        {
            var msg = errorMsg + Environment.NewLine + FormatException(ex);
            this.m_source.TraceEvent(TraceEventType.Error, 1, errorMsg, ex);
        }

        public void Error(string errorMsg)
        {
            this.m_source.TraceEvent(TraceEventType.Error, 1, errorMsg);
        }

        public void Info(string msg)
        {
            this.m_source.TraceEvent(TraceEventType.Information, 2, msg);
        }

        public void Warn(string msg)
        {
            this.m_source.TraceEvent(TraceEventType.Warning, 3, msg);
        }

        #region private

        /// <summary>
        /// 建造异常信息
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        private static string FormatException(Exception ex)
        {
            StringBuilder sb = new StringBuilder();

            Exception logException = ex;
            if (ex.InnerException != null)
                logException = ex.InnerException;

            sb.AppendFormat("Machine    : {0}\r\n", Environment.MachineName);
            sb.AppendFormat("Source     : {0}\r\n", logException.Source);
            sb.AppendFormat("Message    : {0}\r\n", logException.Message);
            if (logException.HelpLink != null)
                sb.AppendFormat("HelpLink   : {0}\r\n", logException.HelpLink);
            sb.AppendFormat("StackTrace : {0}\r\n", logException.StackTrace);
            sb.AppendFormat("TargetSite : {0}\r\n", BuildMethodMessage(logException.TargetSite));

            return sb.ToString();
        }

        /// <summary>
        /// 执行上下文Method信息
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        private static string BuildMethodMessage(MethodBase method)
        {
            StringBuilder methodBuilder = new StringBuilder();
            if (method != null)
            {
                ParameterInfo[] pi = method.GetParameters();
                methodBuilder.AppendFormat("MoudleName: {0}\r\n", method.Module.FullyQualifiedName);
                methodBuilder.AppendFormat("MethodName: {0}\r\n", method.Name);

                methodBuilder.Append("<MethodParameters>\r\n");
                foreach (ParameterInfo info in pi)
                {
                    methodBuilder.Append("<parameter name=\"");
                    methodBuilder.Append(info.Name);
                    methodBuilder.Append("\"  ");
                    methodBuilder.Append("type=\"");
                    methodBuilder.Append(info.ParameterType.ToString());
                    methodBuilder.Append("/>\r\n");
                }
                methodBuilder.Append("</MethodParameters>\r\n");
            }

            return methodBuilder.ToString();
        }

        #endregion
    }
}
